package org.javaforever.gatescore.vue;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.javaforever.gatescore.complexverb.FrontTwinsVerb;
import org.javaforever.gatescore.core.FrontDomain;
import org.javaforever.gatescore.core.FrontEnum;
import org.javaforever.gatescore.core.FrontMethod;
import org.javaforever.gatescore.core.FrontVerb;
import org.javaforever.gatescore.core.Statement;
import org.javaforever.gatescore.core.StatementList;
import org.javaforever.gatescore.core.Writeable;
import org.javaforever.gatescore.core.WriteableUtil;
import org.javaforever.gatescore.exception.ValidateException;
import org.javaforever.gatescore.verb.Activate;
import org.javaforever.gatescore.verb.ActivateAll;
import org.javaforever.gatescore.verb.Add;
import org.javaforever.gatescore.verb.Clone;
import org.javaforever.gatescore.verb.CloneAll;
import org.javaforever.gatescore.verb.Delete;
import org.javaforever.gatescore.verb.DeleteAll;
import org.javaforever.gatescore.verb.Export;
import org.javaforever.gatescore.verb.FindById;
import org.javaforever.gatescore.verb.FindByName;
import org.javaforever.gatescore.verb.ListActive;
import org.javaforever.gatescore.verb.ListAll;
import org.javaforever.gatescore.verb.ListAllByPage;
import org.javaforever.gatescore.verb.SearchByFieldsByPage;
import org.javaforever.gatescore.verb.SearchByName;
import org.javaforever.gatescore.verb.SoftDelete;
import org.javaforever.gatescore.verb.SoftDeleteAll;
import org.javaforever.gatescore.verb.Toggle;
import org.javaforever.gatescore.verb.ToggleOne;
import org.javaforever.gatescore.verb.Update;

public class VueAPIJs implements Comparable<VueAPIJs>,Cloneable,Serializable{
	private static final long serialVersionUID = 8070367386047066447L;
	protected String standardName;
	protected FrontDomain domain;
	protected Set<FrontVerb> verbs = new TreeSet<FrontVerb>();
	protected Set<FrontTwinsVerb> twinsverbs = new TreeSet<FrontTwinsVerb>();
	protected Set<Statement> importStatements = new TreeSet<Statement>();
	protected boolean useLoginBaseUri = false;
	
	public boolean isUseLoginBaseUri() {
		return useLoginBaseUri;
	}

	public void setUseLoginBaseUri(boolean useLoginBaseUri) {
		this.useLoginBaseUri = useLoginBaseUri;
	}

	public VueAPIJs()  throws ValidateException{
		super();
	}
	
	public VueAPIJs(FrontDomain domain)  throws ValidateException{
		super();
		if (domain instanceof FrontEnum) {
			createVueAPIJs((FrontEnum)domain);
		} else {
			this.domain = domain;
			this.standardName = domain.getCapFirstPlural();
			
			FrontVerb listAll = new ListAll(this.domain);
			FrontVerb update = new Update(this.domain);
			FrontVerb delete = new Delete(this.domain);
			FrontVerb add = new Add(this.domain);
			FrontVerb softdelete = new SoftDelete(this.domain);
			FrontVerb findbyid = new FindById(this.domain);
			FrontVerb findbyname = new FindByName(this.domain);
			FrontVerb searchbyname = new SearchByName(this.domain);
			FrontVerb listactive = new ListActive(this.domain);
			FrontVerb listAllByPage = new ListAllByPage(this.domain);
			FrontVerb deleteAll = new DeleteAll(this.domain);
			FrontVerb softDeleteAll = new SoftDeleteAll(this.domain);
			FrontVerb toggle = new Toggle(this.domain);
			FrontVerb toggleOne = new ToggleOne(this.domain);
			FrontVerb searchByFieldsByPage = new SearchByFieldsByPage(this.domain);
			FrontVerb activate = new Activate(this.domain);
			FrontVerb activateAll = new ActivateAll(this.domain);
			FrontVerb export = new Export(this.domain);
			FrontVerb clone = new Clone(this.domain);
			FrontVerb cloneAll = new CloneAll(this.domain);
	
			this.addVerb(listAll);
			this.addVerb(update);
			this.addVerb(delete);
			this.addVerb(add);
			this.addVerb(softdelete);
			this.addVerb(findbyid);
			this.addVerb(findbyname);
			this.addVerb(searchbyname);
			this.addVerb(listactive);
			this.addVerb(listAllByPage);
			this.addVerb(deleteAll);
			this.addVerb(softDeleteAll);
			this.addVerb(toggle);
			this.addVerb(toggleOne);
			this.addVerb(searchByFieldsByPage);
			this.addVerb(activate);
			this.addVerb(activateAll);
			this.addVerb(export);
			this.addVerb(clone);
			this.addVerb(cloneAll);
		}
	}
	
	public void createVueAPIJs(FrontEnum myenum) throws ValidateException{
		this.domain = myenum;
		this.standardName = myenum.getCapFirstPlural();
		
		FrontVerb listAll = new ListAll(this.domain);
		FrontVerb findbyid = new FindById(this.domain);
		FrontVerb findbyname = new FindByName(this.domain);
		FrontVerb searchbyname = new SearchByName(this.domain);
		FrontVerb listactive = new ListActive(this.domain);
		FrontVerb searchByFieldsByPage = new SearchByFieldsByPage(this.domain);
		FrontVerb export = new Export(this.domain);

		this.addVerb(listAll);
		this.addVerb(findbyid);
		this.addVerb(findbyname);
		this.addVerb(searchbyname);
		this.addVerb(listactive);
		this.addVerb(searchByFieldsByPage);
		this.addVerb(export);
	}
	@Override
	public int compareTo(VueAPIJs o) {
		return this.standardName.compareTo(o.getStandardName());
	}
	public String getStandardName() {
		return standardName;
	}
	public void setStandardName(String standardName) {
		this.standardName = standardName;
	}
	public String getFileName() {
		return this.standardName.toLowerCase()+".js";
	}

	public StatementList generateStatementList() throws Exception{
		List<Writeable> sList = new ArrayList<Writeable>();
		if (useLoginBaseUri) {
			sList.add(new Statement(1000L,0,"import request from '@/utils/loginRequest'"));
		}else {
			sList.add(new Statement(1000L,0,"import request from '@/utils/request'"));
		}
		if (this.domain == null || this.domain.isUseOnlyJson() == false) {
			sList.add(new Statement(2000L,0,"import qs from 'qs'"));
		}
		long serial = 3000L;
		for (FrontVerb verb:this.verbs) {
			FrontMethod m = verb.generateApiMethod();
			if (m != null&&m.getAdditionalImports()!=null&&m.getAdditionalImports().size()>0) {
				for (String str:m.getAdditionalImports()) {
					sList.add(new Statement(serial,0,str));
					serial += 1000L;
				}
			}			
		}
		sList.add(new Statement(serial,0,""));
		for (FrontVerb verb:this.verbs) {
			FrontMethod m = verb.generateApiMethod();
			if (m != null) {
				m.setSerial(serial);
				sList.add(m.getMethodStatementList());
				serial += 1000L;
			}			
		}
		
		for (FrontTwinsVerb tv: this.twinsverbs) {
			FrontMethod m = tv.generateApiMethod();
			if (m!= null) {
				m.setSerial(serial);
				sList.add(m.getMethodStatementList());
				serial += 1000L;
			}
		}
		
		return WriteableUtil.merge(sList);
	}
	public FrontDomain getDomain() {
		return domain;
	}
	public void setDomain(FrontDomain domain) {
		this.domain = domain;
	}
	public Set<FrontVerb> getVerbs() {
		return verbs;
	}
	public void setVerbs(Set<FrontVerb> verbs) {
		this.verbs = verbs;
	}	
	public void addVerb(FrontVerb verb) {
		this.verbs.add(verb);
	}
	public Set<FrontTwinsVerb> getTwinsverbs() {
		return twinsverbs;
	}
	public void setTwinsverbs(Set<FrontTwinsVerb> twinsverbs) {
		this.twinsverbs = twinsverbs;
	}
	public Set<Statement> getImportStatements() {
		return importStatements;
	}
	public void setImportStatements(Set<Statement> importStatements) {
		this.importStatements = importStatements;
	}
}
